package com.iflytek.jzcpx.procuracy.common.util;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

/**
 * @author <a href=mailto:ktyi@iflytek.com>伊开堂</a>
 * @date 2022/5/25
 */
public abstract class ThreadPoolUtils {
    protected static final Logger logger = LoggerFactory.getLogger(ThreadPoolUtils.class);

    /** CPU核心数 */
    public static final int CPU_SIZE = Runtime.getRuntime().availableProcessors();

    /**
     * 创建线程池(线程数为CPU核心数)
     */
    public static ThreadPoolExecutor createExecutor() {
        return createExecutor(CPU_SIZE);
    }

    /**
     * 创建线程池
     * @param threadSize 线程数量(core线程数和max线程数都等于该值)
     */
    public static ThreadPoolExecutor createExecutor(int threadSize) {
        return createExecutor(threadSize, "Custom-Thread");
    }

    /**
     * 创建线程池
     * @param threadSize 线程数量(core线程数和max线程数都等于该值)
     * @param threadNamePrefix 线程名前缀, 例: img-format
     */
    public static ThreadPoolExecutor createExecutor(int threadSize, String threadNamePrefix) {
        return createExecutor(threadSize, threadNamePrefix, Integer.MAX_VALUE);
    }

    /**
     * 创建线程池
     * @param threadSize 线程数量(core线程数和max线程数都等于该值)
     * @param threadNamePrefix 线程名前缀, 例: img-format
     * @param queueCapacity 队列长度
     */
    public static ThreadPoolExecutor createExecutor(int threadSize, String threadNamePrefix, int queueCapacity) {
        return createExecutor(threadSize, threadSize, 0, threadNamePrefix, queueCapacity, new ThreadPoolExecutor.AbortPolicy());
    }

    /**
     * 创建线程池
     *
     * @param corePoolSize             线程数量(core线程数和max线程数都等于该值)
     * @param keepAliveSec
     * @param threadNamePrefix         线程名前缀, 例: img-format
     * @param queueCapacity            队列长度
     * @param rejectedExecutionHandler 拒绝策略
     *
     * @return
     */
    public static ThreadPoolExecutor createExecutor(int corePoolSize, int maximumPoolSize, int keepAliveSec,
            String threadNamePrefix, int queueCapacity, RejectedExecutionHandler rejectedExecutionHandler) {
        Assert.isTrue(corePoolSize > 0, "线程数threadSize必须大于0");
        Assert.isTrue(queueCapacity > 0, "队列容量queueCapacity必须大于0");

        ThreadFactory threadFactory = new ThreadFactory() {
            final AtomicLong count = new AtomicLong(0L);
            final ThreadFactory factory = Executors.defaultThreadFactory();

            @Override
            public Thread newThread(Runnable r) {
                String name = String.format(threadNamePrefix + "-%d", count.getAndIncrement());
                Thread thread = factory.newThread(r);
                thread.setName(name);
                thread.setDaemon(false);
                thread.setUncaughtExceptionHandler((t, e) -> logger.error("线程 " + t + " 异常结束", e));
                return thread;
            }
        };
        ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveSec,
                                                             TimeUnit.SECONDS, new LinkedBlockingQueue<>(queueCapacity),
                                                             threadFactory, rejectedExecutionHandler);
        return executor;
    }

    /**
     * 获取线程池监控信息
     *
     * @param executor
     *
     * @return 格式: 执行中线程数: 5(50%, 2-6-8-10), 队列内任务数: 300(30%, 1000: 300|700)
     */
    public static String poolInfo(ThreadPoolExecutor executor) {
        if (executor == null) {
            return null;
        }

        // 核心线程数
        int corePoolSize = executor.getCorePoolSize();
        // 历史线程数峰值
        int largestPoolSize = executor.getLargestPoolSize();
        // 最大线程数
        int maximumPoolSize = executor.getMaximumPoolSize();
        // 当前活跃线程数(正在执行任务)
        int activeCount = executor.getActiveCount();
        // 当前线程数(可能部分在休眠)
        int poolSize = executor.getPoolSize();
        long taskCount = executor.getTaskCount();
        long completedTaskCount = executor.getCompletedTaskCount();

        BlockingQueue<Runnable> queue = executor.getQueue();
        // 队列内任务数
        int queueSize = queue.size();
        // 队列剩余容量
        int remainingCapacity = queue.remainingCapacity();
        // 队列总容量
        int queueCapacity = queueSize + remainingCapacity;

        int threadPercent = (int) (activeCount / (float) maximumPoolSize * 100);
        int queuePercent = (int) (queueSize / (float) queueCapacity * 100);

        // 执行中线程数: 5(50%, 2-8-8-10), 队列内任务数: 300(30%, 1000: 300|700)
        StringBuilder sb = new StringBuilder("活动线程数: ");
        sb.append(activeCount).append("(").append(threadPercent).append("%, ");
        sb.append(corePoolSize).append("-").append(poolSize).append("-").append(largestPoolSize).append("-").append(
                maximumPoolSize).append("), ");
        sb.append("已处理: ").append(completedTaskCount).append("(").append(taskCount).append("), ");
        sb.append("队列积压: ").append(queueSize).append("(").append(queuePercent).append("%, ").append(queueCapacity)
          .append(": ").append(queueSize).append("+").append(remainingCapacity).append(")");
        return sb.toString();
    }

}
